package com.hibikiluler.javalearning.Config;


import com.hibikiluler.javalearning.Config.Security.Contents.SecurityContents;
import com.hibikiluler.javalearning.Config.Security.Header.JwtAccessDeniedHandler;
import com.hibikiluler.javalearning.Config.Security.Header.JwtAuthenticationEntryPoint;
import com.hibikiluler.javalearning.Config.Security.Header.JwtAuthenticationFilter;
import com.hibikiluler.javalearning.Config.Security.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 权限基本配置
 */
@Configuration
@EnableWebSecurity //首先,EnableWebSecurity注解是个组合注解,他的注解中,又使用了@EnableGlobalAuthentication注解,
// 作用,1: 加载了WebSecurityConfiguration配置类, 配置安全认证策略。2: 加载了AuthenticationConfiguration, 配置了认证信息。
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtAuthenticationFilter authenticationFilter;



    //一般用于配置白名单  在SpringSecurity项目中有新版本的规则 此处为5.7版本之前的
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers(SecurityContents.WHITE_LIST);
    }

    //Security的核心配置  在SpringSecurity项目中有新版本的规则 此处为5.7版本之前的
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //1. 使用jwt，首先关闭跨域攻击
        http.csrf().disable();
        //2. 关闭session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //3.  请求认证之后才能访问。除了白名单以外的资源
        http.authorizeRequests().antMatchers("/user/login").anonymous()
                .anyRequest().authenticated();
        //4. 关闭缓存
        http.headers().cacheControl();
        //5. token 过滤器 校验token
        http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
        //6. 没有登录 没有权限访问自定义返回结果
        http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).accessDeniedHandler(jwtAccessDeniedHandler);
    }

    /**
     * 自定义逻辑配置 配置到security中认证  在SpringSecurity项目中有新版本的规则 此处为5.7版本之前的
     * 在studyproject项目中，相当于添加我们自定义实现的UserDetailsService和解码器
     * @param auth
     * @throws Exception 
     */
    @Override  
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
